#include "frame_queue.h"

int frame_queue_init(FrameQueue *f, PacketQueue *pktq, int max_size, int keep_last)
{
    int i;
    memset(f, 0, sizeof(FrameQueue));
    if (!(f->mutex = SDL_CreateMutex())) {
        av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());
        return AVERROR(ENOMEM);
    }
    if (!(f->cond = SDL_CreateCond())) {
        av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
        return AVERROR(ENOMEM);
    }
    f->pktq = pktq;
    f->max_size = FFMIN(max_size, FRAME_QUEUE_SIZE); //  这里是3个视频帧，视频传来的max_size是3
    f->keep_last = !!keep_last;
    for (i = 0; i < f->max_size; i++)
        if (!(f->queue[i].frame = av_frame_alloc())) //直接分配了3个frame
            return AVERROR(ENOMEM);
    return 0;
}
/* return the number of undisplayed frames in the queue */
int frame_queue_nb_remaining(FrameQueue *f)
{
    return f->size - f->rindex_has_shown;
}

void frame_queue_signal(FrameQueue *f)
{
    SDL_LockMutex(f->mutex);
    SDL_CondSignal(f->cond);
    SDL_UnlockMutex(f->mutex);
}

//获取一个可写节点的地址
Frame *frame_queue_peek_writable(FrameQueue *f)
{
    /* wait until we have space to put a new frame */
    SDL_LockMutex(f->mutex);
    while (f->size >= f->max_size &&
           !f->pktq->abort_request) //frame 取不走，这里会等待,这个队列视频只有3个，音频有9个
	{
		printf("packet to frame waiting...size:%d,max_size:%d\n",f->size,f->max_size);
        SDL_CondWait(f->cond, f->mutex);
    }
    SDL_UnlockMutex(f->mutex);

    if (f->pktq->abort_request)
        return NULL;

    return &f->queue[f->windex];
}

//(数据写好以后） 把写指针向下移动一个,并告知已有数据
void frame_queue_push(FrameQueue *f)
{
    if (++f->windex == f->max_size)
        f->windex = 0;
    SDL_LockMutex(f->mutex);
    f->size++;
    SDL_CondSignal(f->cond);
    SDL_UnlockMutex(f->mutex);
}

//frame 有2种状态，一种是保留最后一帧(此时rindex_has_shown可由0变为1），一种是正常
//所以把 rindex_shown 改为 rindex_has_shown 意义更明确
//
Frame *frame_queue_peek_readable(FrameQueue *f)
{
    /* wait until we have a readable a new frame */
    SDL_LockMutex(f->mutex);
    while (f->size - f->rindex_has_shown <= 0 &&
           !f->pktq->abort_request) {
        SDL_CondWait(f->cond, f->mutex);
    }
    SDL_UnlockMutex(f->mutex);

    if (f->pktq->abort_request)
        return NULL;

    return &f->queue[(f->rindex + f->rindex_has_shown) % f->max_size];
}
//下面三个函数时获取当前帧,获取下一帧和获取最后一帧(最后读的那个帧) 接口
Frame *frame_queue_peek(FrameQueue *f)
{
    return &f->queue[(f->rindex + f->rindex_has_shown) % f->max_size];
}

 Frame *frame_queue_peek_next(FrameQueue *f)
{
    return &f->queue[(f->rindex + f->rindex_has_shown + 1) % f->max_size];
}
 Frame *frame_queue_peek_last(FrameQueue *f)
{
    return &f->queue[f->rindex];
}

static void frame_queue_unref_item(Frame *vp)
{
    av_frame_unref(vp->frame);
    avsubtitle_free(&vp->sub);
}
//出队列,同时将rindex加1,size减1,并给通知信号
void frame_queue_next(FrameQueue *f)
{
    if (f->keep_last && !f->rindex_has_shown) { //当keep_last(保留最后一帧)时,rindex_shown会被置为1
        f->rindex_has_shown = 1;
        return;
    }
    frame_queue_unref_item(&f->queue[f->rindex]); //释放当前帧,rindex 加1
    if (++f->rindex == f->max_size)
        f->rindex = 0;
    SDL_LockMutex(f->mutex);
    f->size--;
    SDL_CondSignal(f->cond);  //跟踪一下这个信号通知给了谁,后面的流程
    SDL_UnlockMutex(f->mutex);
}

/* return last shown position */ //仅在rindex_has_shown为真时有效
 int64_t frame_queue_last_pos(FrameQueue *f)
 {  //仅在保留最后帧时有效
    Frame *fp = &f->queue[f->rindex];
    if (f->rindex_has_shown && fp->serial == f->pktq->serial)
        return fp->pos;
    else
        return -1;
}

void frame_queue_destory(FrameQueue *f)
{
    int i;
    for (i = 0; i < f->max_size; i++) {
        Frame *vp = &f->queue[i];
        frame_queue_unref_item(vp);
        av_frame_free(&vp->frame);
    }
    SDL_DestroyMutex(f->mutex);
    SDL_DestroyCond(f->cond);
}
